#include <jni.h>
#include <string>
#include <opencv2/opencv.hpp>
#include <android/native_window_jni.h>
#include "macro.h"

using namespace cv;
DetectionBasedTracker *tracker = 0;
ANativeWindow *window;

class CascadeDetectorAdapter : public DetectionBasedTracker::IDetector {
public:
    CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector) :
            IDetector(),
            Detector(detector) {
//        CV_Assert(detector);
    }

    //检测到人脸 调用 Mat == Bitmap
    void detect(const cv::Mat &Image, std::vector<cv::Rect> &objects) {
        Detector->detectMultiScale(Image, objects, scaleFactor, minNeighbours, 0, minObjSize,
                                   maxObjSize);
    }

    virtual ~CascadeDetectorAdapter() {
    }

private:
    CascadeDetectorAdapter();

    cv::Ptr<cv::CascadeClassifier> Detector;
};

extern "C"
JNIEXPORT void JNICALL
Java_com_zsd_android_opencvface_OpenCVJni_init(JNIEnv *env, jobject instance, jstring path_) {
    const char *path = env->GetStringUTFChars(path_, 0);

    //创建检测器
    //智能指针
    Ptr<CascadeClassifier> classifier = makePtr<CascadeClassifier>(path);
    Ptr<CascadeDetectorAdapter> mainDetector = makePtr<CascadeDetectorAdapter>(classifier);

    //创建跟踪器
    //智能指针
    Ptr<CascadeClassifier> classifier1 = makePtr<CascadeClassifier>(path);
    Ptr<CascadeDetectorAdapter> trackingDetector = makePtr<CascadeDetectorAdapter>(classifier1);

    DetectionBasedTracker::Parameters detectorParams;
    tracker = new DetectionBasedTracker(mainDetector, trackingDetector, detectorParams);
    tracker->run();
    env->ReleaseStringUTFChars(path_, path);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_zsd_android_opencvface_OpenCVJni_postData(JNIEnv *env, jobject instance, jbyteArray data_,
                                                   jint width, jint height, jint cameraId) {
    jbyte *data = env->GetByteArrayElements(data_, NULL);

    Mat src(height + height / 2, width, CV_8UC1, data);
    cvtColor(src, src, COLOR_YUV2RGBA_NV21);
    if (1 == cameraId) {
        //前置摄像头
        //逆时针旋转90度
        rotate(src, src, ROTATE_90_COUNTERCLOCKWISE);
        //镜像，1代表水平翻转， 0代表垂直翻转
        flip(src, src, 1);
    } else {
        //后置摄像头
        //顺时针旋转90度
        rotate(src, src, ROTATE_90_CLOCKWISE);
    }
    //转化成灰度图
    Mat gray;
    cvtColor(src, gray, COLOR_RGBA2GRAY);
    //增强对比度
    equalizeHist(gray, gray);
    //检测人脸
    std::vector<Rect> faces;
    tracker->process(gray);
    tracker->getObjects(faces);
    for (Rect face : faces) {
        rectangle(src, face, Scalar(255, 0, 255));
    }
    if (window) {
        ANativeWindow_setBuffersGeometry(window, src.cols, src.rows, WINDOW_FORMAT_RGBA_8888);
        ANativeWindow_Buffer window_buffer;
        do {
            LOGE("window 初始化成功");
            if (ANativeWindow_lock(window, &window_buffer, 0)) {
                ANativeWindow_release(window);
                window = 0;
                LOGE("window 锁定失败");
                break;
            }
            uint8_t *dst_data = static_cast<uint8_t *>(window_buffer.bits);
            //stride:一行多少个数据(RGBA) * 4
            int dst_linesize = window_buffer.stride * 4;
            //一行一行拷贝
            for (int i = 0; i < window_buffer.height; ++i) {
                memcpy(dst_data + i * dst_linesize, src.data + i * src.cols * 4, dst_linesize);
            }
            //提交刷新
            ANativeWindow_unlockAndPost(window);
        } while (0);
    }
    src.release();
    gray.release();

    env->ReleaseByteArrayElements(data_, data, 0);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_zsd_android_opencvface_OpenCVJni_setSurface(JNIEnv *env, jobject instance,
                                                     jobject mSurface) {
    if (window) {
        ANativeWindow_release(window);
        window = 0;
    }
    window = ANativeWindow_fromSurface(env, mSurface);
}